package com.bjy.qa.agent.transport.command;

import com.alibaba.fastjson.JSON;
import com.bjy.qa.agent.model.KeyValueStore;
import com.bjy.qa.agent.response.Response;
import com.bjy.qa.agent.transport.http.HttpService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Http 执行器
 */
public class HttpExecuteCommand extends ExecuteCommand {
    protected static final Logger logger = LoggerFactory.getLogger(HttpExecuteCommand.class);
    private static final String SPLIT = "|";
    protected String url;
    protected String method;
    protected List<KeyValueStore> params;
    private HttpService httpService;

    /**
     * 构造函数
     * @param httpService
     * @param resultId 运行结果 id
     * @param caseId 用例 id
     * @param ic 迭代次数（iteration count）
     * @param url 请求 url
     * @param method 请求方法
     * @param desc 用例描述
     */
    public HttpExecuteCommand(HttpService httpService, String resultId, String caseId, String ic, String url, String method, String desc) {
        super(resultId, caseId, ic, desc);
        this.httpService = httpService;
        this.url = url;
        this.method = method;
    }

    /**
     * 执行命令，实现了父类的抽象方法，也是主功能
     * @param params 参数列表
     * @return
     */
    @Override
    public Response execute(List<KeyValueStore> params) {
        Map headers = getHttpHeaders(params);
        this.params = removedHttpHeaders(params);

        if (logger.isInfoEnabled()) {
            logger.info("Http request start: url={}, method={}, headers={}, params={}", new Object[]{this.url, this.method, headers, getParamsAsString(this.params)});
        }
        httpService.setHeaders(headers);

        Response response = null;
        if (isEntityRequest(this.method)) {
            response = httpService.entityRequest(resultId, caseId, ic, this.url, this.method, this.params);
            this.method = fixMethod(this.method);
        } else {
            response = httpService.get(resultId, caseId, ic, this.url, this.params);
        }

        if (logger.isInfoEnabled()) {
            logger.info("Http Execute : method={}, url={}, params={}, response={}", new Object[]{this.method, this.url, getParamsAsString(params), response});
        }
        return response;
    }

    private static List<KeyValueStore> splitParameters(List<KeyValueStore> params) {
        if (params == null) {
            return params;
        }
        List result = new ArrayList(params.size());
        for (KeyValueStore param : params) {
            Object value = param.getValue();
            if (((value instanceof String)) && (((String) value).contains("|"))) {
                String[] valueArray = StringUtils.split((String) value, "|");
                for (int i = 0; i < valueArray.length; i++)
                    result.add(new KeyValueStore(param.getName(), valueArray[i].trim()));
            } else {
                result.add(param);
            }
        }
        return result;
    }

    /**
     * 当 method 传入的是 binary 时，修正成 post
     * @param method 请求方法
     * @return
     */
    public static String fixMethod(String method) {
        if ("binary".equalsIgnoreCase(method)) {
            return "POST";
        } else if ("GET/ENTITY".equalsIgnoreCase(method)) {
            return "GET";
        }
        return method;
    }

    /**
     * 判断是否是需要实体请求（entityRequest）
     * @param method 请求方法
     * @return
     */
    protected boolean isEntityRequest(String method) {
        return ("GET/ENTITY".equalsIgnoreCase(method)) || ("POST".equalsIgnoreCase(method)) || ("PUT".equalsIgnoreCase(method)) || ("DELETE".equalsIgnoreCase(method)) || ("binary".equalsIgnoreCase(method));
    }

    /**
     * 将 List<KeyValueStore> 转成 Map
     * @param params 参数列表
     * @return Map
     */
    protected Map getHttpHeaders(List<KeyValueStore> params) {
        for (KeyValueStore param : params) {
            if (isHttpHeaders(param)) {
                return tryParseObject(param.getValue());
            }
        }
        return null;
    }

    /**
     * 将参数 List<KeyValueStore> 转成参数字符串（在 post form 表单或 get ? 后的参数都会用到）
     * 例：["name"="张三", "age"=18, "sex"="男"] 返回 name=张三&age=18&sex=男
     * @param params 参数列表
     * @return 参数字符串
     */
    protected String getParamsAsString(List<KeyValueStore> params) {
        if (params == null) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        for (KeyValueStore kv : params) {
            sb.append(kv.getName()).append("=").append(kv.getValue()).append("&");
        }

        return sb.toString();
    }

    /**
     * 从传入的参数列表中，删除所有 http headers 参数
     * @param params 参数列表
     * @return 删除 http headers 参数后的参数列表
     */
    protected List<KeyValueStore> removedHttpHeaders(List<KeyValueStore> params) {
        if (params == null) {
            return null;
        }
        List result = new ArrayList();
        for (KeyValueStore param : params) {
            if (!isHttpHeaders(param))
                result.add(param);
        }
        return result;
    }

    /**
     * 判断是否是 http headers 参数（key="http-headers" 表示是 head 参数）
     * @param param 参数
     * @return 是 http headers 参数返回 true，否则返回 false
     */
    protected boolean isHttpHeaders(KeyValueStore param) {
        return param.getName().equalsIgnoreCase("http-headers");
    }

    /**
     * 返回包裹在 html a 标签中的 URL（只有 get 请求会包裹在 a 标签中），如果有参数也会带上
     * @param url URL
     * @param params 参数列表
     * @return
     */
    protected String showReportUrlWithLink(String url, List<KeyValueStore> params) {
        if (!"get".equals(this.method)) return url;
        StringBuilder urlBuffer = new StringBuilder();
        urlBuffer.append("<a href=\"").append(url).append("?");
        if ((params != null) && (!params.isEmpty())) {
            for (KeyValueStore param : params) {
                urlBuffer.append(param.getName()).append("=").append(param.getValue()).append("&");
            }
            urlBuffer.deleteCharAt(urlBuffer.lastIndexOf("&"));
        }
        urlBuffer.append("\">").append(url).append("</a>");
        return urlBuffer.toString();
    }

    /**
     * 获得测试报告（测试结果上报使用）
     * @return
     */
    @Override
    public String toReportInfo() {
        return String.format("使用 %s 方式调用 HTTP 接口 %s", new Object[]{StringUtils.isBlank(this.method) ? "get" : this.method, showReportUrlWithLink(this.url, this.params)});
    }

    /**
     * json字符串转map对象
     * @param value json字符串
     * @return Map
     */
    private static Map tryParseObject(Object value) {
        if (value instanceof String) {
            try {
                Map map = JSON.parseObject(value.toString());
                if (null == map) {
                    map = new HashMap();
                }
                return map;
            } catch (Exception e) {
                throw new RuntimeException(String.format("<%s>尝试转JSONObject失败, error message=%s", new Object[]{value, e.getMessage()}), e);
            }
        } else if (value instanceof Map) {
            return (Map) value;
        } else {
            throw new RuntimeException(String.format("<%s>返回map失败", new Object[]{value}));
        }
    }
}
